<template>
  <div class="barcode-scanner">
    <el-dialog
      title="扫描商品条码"
      :visible.sync="visible"
      width="400px"
      :before-close="handleClose"
      custom-class="scanner-dialog"
    >
      <div v-if="!hasError" class="scanner-container">
        <div id="interactive" class="viewport"></div>
        <div class="scan-region-highlight"></div>
        <div class="scan-region-highlight-svg"></div>
      </div>
      
      <!-- 错误状态显示 -->
      <div v-else class="error-container">
        <i class="el-icon-warning-outline"></i>
        <p>{{ errorMessage }}</p>
        <el-button type="primary" @click="retryAccess">重试</el-button>
      </div>

      <div v-if="!hasError" class="scanner-tips">
        <p>请将商品条码对准扫描框</p>
        <p v-if="lastResult" class="last-result">最后扫描: {{ lastResult }}</p>
      </div>

      <div slot="footer" class="dialog-footer">
        <el-button @click="handleClose">取 消</el-button>
        <el-button 
          v-if="!hasError && hasTorch" 
          type="primary" 
          @click="toggleTorch"
        >
          {{ torchOn ? '关闭闪光灯' : '打开闪光灯' }}
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Quagga from 'quagga'

export default {
  name: 'BarcodeScanner',
  data() {
    return {
      visible: false,
      lastResult: '',
      torchOn: false,
      hasError: false,
      errorMessage: '',
      hasTorch: false,
      initAttempts: 0,
      maxAttempts: 3
    }
  },
  methods: {
    show() {
      this.visible = true
      this.hasError = false
      this.errorMessage = ''
      this.$nextTick(() => {
        this.initQuagga()
      })
    },
    handleClose() {
      this.stopScanner()
      this.visible = false
      this.hasError = false
      this.errorMessage = ''
      this.initAttempts = 0
    },
    async initQuagga() {
      if (this.initAttempts >= this.maxAttempts) {
        this.handleError('多次尝试后仍无法访问摄像头，请检查设备权限设置')
        return
      }

      this.initAttempts++

      try {
        // 先检查是否支持摄像头
        const devices = await navigator.mediaDevices.enumerateDevices()
        const hasCamera = devices.some(device => device.kind === 'videoinput')
        
        if (!hasCamera) {
          throw new Error('未检测到摄像头设备')
        }

        // 请求摄像头权限
        await navigator.mediaDevices.getUserMedia({ video: true })

        Quagga.init({
          inputStream: {
            name: "Live",
            type: "LiveStream",
            target: "#interactive",
            constraints: {
              facingMode: "environment",
              aspectRatio: { min: 1, max: 2 }
            },
          },
          locator: {
            patchSize: "medium",
            halfSample: true
          },
          numOfWorkers: 2,
          decoder: {
            readers: [
              "ean_reader",
              "ean_8_reader",
              "upc_reader",
              "upc_e_reader"
            ]
          },
          locate: true
        }, (err) => {
          if (err) {
            this.handleError('初始化扫码器失败，请重试')
            return
          }

          Quagga.start()
          this.checkTorchSupport()
          Quagga.onDetected(this.onBarcodeDetected)
        })

      } catch (error) {
        let message = '无法访问摄像头，'
        if (error.name === 'NotAllowedError') {
          message += '请授予摄像头访问权限'
        } else if (error.name === 'NotFoundError') {
          message += '未找到可用的摄像头设备'
        } else {
          message += '请确保设备支持摄像头并已授予权限'
        }
        this.handleError(message)
      }
    },
    handleError(message) {
      this.hasError = true
      this.errorMessage = message
      this.stopScanner()
    },
    retryAccess() {
      this.hasError = false
      this.errorMessage = ''
      this.initQuagga()
    },
    stopScanner() {
      try {
        Quagga.stop()
      } catch (error) {
        console.error('停止扫码器时出错:', error)
      }
    },
    async checkTorchSupport() {
      try {
        const track = Quagga.CameraAccess.getActiveTrack()
        if (track && track.getCapabilities().torch) {
          this.hasTorch = true
        }
      } catch (error) {
        console.log('设备不支持闪光灯控制')
        this.hasTorch = false
      }
    },
    onBarcodeDetected(result) {
      const code = result.codeResult.code
      this.lastResult = code
      this.$emit('barcode-detected', code)
      
      // 播放提示音
      this.playBeep()
      
      // 震动反馈
      if (navigator.vibrate) {
        navigator.vibrate(100)
      }
    },
    playBeep() {
      try {
        const audio = new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...')
        audio.play().catch(() => {
          // 忽略自动播放限制导致的错误
        })
      } catch (error) {
        console.log('播放提示音失败:', error)
      }
    },
    async toggleTorch() {
      try {
        const track = Quagga.CameraAccess.getActiveTrack()
        if (track && track.getCapabilities().torch) {
          await track.applyConstraints({
            advanced: [{ torch: !this.torchOn }]
          })
          this.torchOn = !this.torchOn
        }
      } catch (error) {
        this.$message.warning('控制闪光灯失败')
        this.hasTorch = false
      }
    }
  },
  beforeDestroy() {
    this.stopScanner()
  }
}
</script>

<style lang="scss" scoped>
.scanner-dialog {
  .scanner-container {
    position: relative;
    width: 100%;
    height: 300px;
    overflow: hidden;
    background: #000;
  }

  .error-container {
    text-align: center;
    padding: 40px 20px;
    
    i {
      font-size: 48px;
      color: #E6A23C;
      margin-bottom: 20px;
    }
    
    p {
      color: #606266;
      margin-bottom: 20px;
    }
  }

  #interactive.viewport {
    position: relative;
    width: 100%;
    height: 100%;
    
    > video {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }

  .scan-region-highlight {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 200px;
    height: 100px;
    border: 2px solid #fff;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
  }

  .scanner-tips {
    margin-top: 15px;
    text-align: center;
    color: #666;
    
    .last-result {
      color: var(--primary-color);
      font-weight: bold;
    }
  }
}
</style> 